package com.tsfyun.scm.service.impl.file;

import cn.hutool.core.collection.CollectionUtil;
import com.github.pagehelper.PageInfo;
import com.tsfyun.common.base.config.OrikaBeanMapper;
import com.tsfyun.common.base.config.ValidationUtil;
import com.tsfyun.common.base.dto.*;
import com.tsfyun.common.base.enums.FileTypeEnum;
import com.tsfyun.common.base.exception.ServiceException;
import com.tsfyun.common.base.extension.ServiceImpl;
import com.tsfyun.common.base.security.LoginVO;
import com.tsfyun.common.base.security.SecurityUtil;
import com.tsfyun.common.base.util.StringUtils;
import com.tsfyun.common.base.util.TsfPreconditions;
import com.tsfyun.common.base.vo.FileQtyVO;
import com.tsfyun.common.base.vo.UploadFileVO;
import com.tsfyun.scm.config.properties.FileProperties;
import com.tsfyun.scm.entity.file.UploadFile;
import com.tsfyun.scm.mapper.file.UploadFileMapper;
import com.tsfyun.scm.service.file.IUploadFileService;
import com.tsfyun.scm.vo.base.ClientFileVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import tk.mybatis.mapper.entity.Example;
import tk.mybatis.mapper.weekend.WeekendSqls;

import java.io.File;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@RefreshScope
@Slf4j
@Service
public class UploadFileServiceImpl extends ServiceImpl<UploadFile> implements IUploadFileService {

    @Autowired
    private UploadFileMapper uploadFileMapper;

    //文件存放目录
    @Value(value = "${file.directory}")
    private String fileDirectory;

    @Autowired
    private FileProperties fileProperties;

    //图片文件类型
    private List<String> images = Arrays.asList("jpg", "jpeg", "pjpeg", "gif", "png", "bmp", "tif", "xbm", "tif", "pjp", "jfif", "avif", "ico", "tiff", "svg", "bpm", "svgz", "webp");

    //其他文件类型
    private List<String> otherFiles = Arrays.asList("pdf", "xls", "xlsx", "doc", "docx", "ppt", "pptx", "txt", "zip", "rar", "7z", "jpg", "jpeg", "gif", "png", "bmp", "tif");

    @Autowired
    private OrikaBeanMapper beanMapper;

    @Autowired
    private ValidationUtil validationUtil;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public UploadFileVO upload(UploadFileDTO dto) {
        LoginVO loginVO = SecurityUtil.getCurrent();
        if (Objects.nonNull(loginVO)) {
            dto.setUid(loginVO.getPersonId().toString());
            dto.setUname(loginVO.getPersonName());
        }else{
            dto.setUid("-1");
            dto.setUname("系统");
        }
        validationUtil.validate(dto);
        //实际文件名称
        String originalFilename = StringUtils.removeSpecialSymbol(dto.getFile().getOriginalFilename());
        //文件后缀
        String fileExtension = originalFilename.substring(originalFilename.lastIndexOf('.') + 1).toLowerCase();
        if (Objects.equals(dto.getFileType(), FileTypeEnum.IMAGE.getCode())) {
            TsfPreconditions.checkArgument(images.contains(fileExtension), new ServiceException("您上传的图片文件格式不正确"));
        } else {
            TsfPreconditions.checkArgument(otherFiles.contains(fileExtension), new ServiceException("您上传的文件格式不正确"));
        }
        //校验单据类型和文件业务类型
        List<Map<String, Object>> docTypes = fileProperties.getDocType();
        if (CollectionUtil.isNotEmpty(docTypes)) {
            long cnt = docTypes.stream().filter(r -> dto.getDocType().equals(StringUtils.null2EmptyWithTrim(r.get("code")))).count();
            if (cnt < 1) {
                throw new ServiceException("文件单据类型错误");
            }
        }
        List<Map<String, Object>> businessTypes = fileProperties.getBusinessType();
        if (CollectionUtil.isNotEmpty(businessTypes)) {
            long cnt = businessTypes.stream().filter(r -> dto.getBusinessType().equals(StringUtils.null2EmptyWithTrim(r.get("code")))).count();
            if (cnt < 1) {
                throw new ServiceException("文件单据业务类型错误");
            }
        }
        //文件存放路径
        String path = fileDirectory + String.format("%s/%s/", dto.getDocType(), dto.getBusinessType());
        //文件存放名称（随机生成uuid）
        String sysFileName = StringUtils.UUID() + "." + fileExtension;
        UploadFile uploadFile = new UploadFile();
        uploadFile.setDocId(dto.getDocId());
        uploadFile.setDocType(dto.getDocType());
        uploadFile.setBusinessType(dto.getBusinessType());
        uploadFile.setMemo(dto.getMemo());
        uploadFile.setName(originalFilename);
        uploadFile.setNname(sysFileName);
        uploadFile.setPath(path);
        uploadFile.setUid(dto.getUid());
        uploadFile.setUname(dto.getUname());
        uploadFile.setExtension(fileExtension);
        uploadFile.setIsDelete(Boolean.FALSE);
        uploadFile.setCreateBy(StringUtils.null2EmptyWithTrim(dto.getUid()).concat("/").concat(StringUtils.null2EmptyWithTrim(dto.getUname())));
        uploadFile.setDateCreated(LocalDateTime.now());
        try {
            //创建文件存放目录
            File dirFile = new File(uploadFile.getPath());
            if (!dirFile.exists()) {
                dirFile.mkdirs();
            }
            dto.getFile().transferTo(new File(uploadFile.getPath().concat(uploadFile.getNname())));
        } catch (Exception e) {
            log.error("文件保存失败：",e);
            throw new ServiceException("文件上传失败,请稍后重试");
        }
        super.saveNonNull(uploadFile);
        //仅仅允许存在一个相同类型的文件
        if(Objects.equals(dto.getIsOnlyOne(),Boolean.TRUE)){
            uploadFileMapper.invalidOthers(uploadFile.getId(),uploadFile.getDocId(),uploadFile.getDocType(),uploadFile.getBusinessType());
        }
        return beanMapper.map(uploadFile, UploadFileVO.class);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<Long> ids) {
        TsfPreconditions.checkArgument(!CollectionUtils.isEmpty(ids) && ids.size() <= 10, new ServiceException("一次最多只能删除10条"));
        uploadFileMapper.deletes(ids);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByDocId(String docId) {
        uploadFileMapper.deleteByDocId(docId);
    }

    @Override
    public List<UploadFileVO> list(FileQTO fileQTO) {
        UploadFile condition = new UploadFile();
        condition.setDocId(fileQTO.getDocId());
        condition.setDocType(fileQTO.getDocType());
        if (StringUtils.isNotEmpty(fileQTO.getBusinessType())) {
            condition.setBusinessType(fileQTO.getBusinessType());
        }
        condition.setIsDelete(Boolean.FALSE);
        List<UploadFile> list = super.list(condition);
        if (CollectionUtil.isNotEmpty(list)) {
            //中文转义
            List<Map<String, Object>> docTypes = fileProperties.getDocType();
            List<Map<String, Object>> businessTypes = fileProperties.getBusinessType();
            Map<String, Object> docTypeMap = docTypes.stream().collect(
                    Collectors.toMap(x -> StringUtils.null2EmptyWithTrim(x.get("code")),
                            x -> StringUtils.null2EmptyWithTrim(x.get("name"))));
            Map<String, Object> businessTypesMap = businessTypes.stream().collect(
                    Collectors.toMap(x -> StringUtils.null2EmptyWithTrim(x.get("code")),
                            x -> StringUtils.null2EmptyWithTrim(x.get("name"))));
            List<UploadFileVO> datas = beanMapper.mapAsList(list, UploadFileVO.class);
            datas.stream().forEach(r -> {
                r.setDocTypeDesc(StringUtils.null2EmptyWithTrim(docTypeMap.get(r.getDocType())));
                r.setBusinessTypeDesc(StringUtils.null2EmptyWithTrim(businessTypesMap.get(r.getBusinessType())));
            });
            //按创建时间降序排列
            datas = datas.stream().sorted(Comparator.comparing(UploadFileVO::getDateCreated).reversed()).collect(Collectors.toList());
            return datas;
        }
        return null;
    }

    @Override
    public Integer count(FileQTO fileQTO) {
        return uploadFileMapper.count(fileQTO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void relateFile(String docId, FileDTO dto) {
        if (Objects.nonNull(dto)) {
            UploadFile update = new UploadFile();
            update.setDocId(docId);
            uploadFileMapper.updateByExampleSelective(update, Example.builder(UploadFile.class).where(
                    WeekendSqls.<UploadFile>custom()
                            .andEqualTo(UploadFile::getDocId, dto.getDocId())
                            .andEqualTo(UploadFile::getDocType, dto.getDocType())
                            .andEqualTo(UploadFile::getIsDelete, Boolean.FALSE)
            ).build());
        }
    }

    @Override
    public List<FileQtyVO> countGroup(FileQTO fileQTO) {
        return uploadFileMapper.countGroup(fileQTO);
    }

    @Override
    public List<ClientFileVO> findByFile(String docId, String docType, String businessType) {
        return uploadFileMapper.findByFile(docId, docType, businessType);
    }

    @Override
    public List<UploadFileVO> list(PaginationDto page, FileQTO fileQTO) {
        UploadFile condition = new UploadFile();
        condition.setDocId(fileQTO.getDocId());
        condition.setDocType(fileQTO.getDocType());
        if (StringUtils.isNotEmpty(fileQTO.getBusinessType())) {
            condition.setBusinessType(fileQTO.getBusinessType());
        }
        condition.setIsDelete(Boolean.FALSE);
        PageInfo<UploadFile> dataPage = super.pageList(condition,page.getPage(),page.getLimit(),"date_created");
        if (CollectionUtil.isNotEmpty(dataPage.getList())) {
            //中文转义
            List<Map<String, Object>> docTypes = fileProperties.getDocType();
            List<Map<String, Object>> businessTypes = fileProperties.getBusinessType();
            Map<String, Object> docTypeMap = docTypes.stream().collect(
                    Collectors.toMap(x -> StringUtils.null2EmptyWithTrim(x.get("code")),
                            x -> StringUtils.null2EmptyWithTrim(x.get("name"))));
            Map<String, Object> businessTypesMap = businessTypes.stream().collect(
                    Collectors.toMap(x -> StringUtils.null2EmptyWithTrim(x.get("code")),
                            x -> StringUtils.null2EmptyWithTrim(x.get("name"))));
            List<UploadFileVO> datas = beanMapper.mapAsList(dataPage.getList(), UploadFileVO.class);
            datas.stream().forEach(r -> {
                r.setDocTypeDesc(StringUtils.null2EmptyWithTrim(docTypeMap.get(r.getDocType())));
                r.setBusinessTypeDesc(StringUtils.null2EmptyWithTrim(businessTypesMap.get(r.getBusinessType())));
            });
            return datas;
        }
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchUpdateDocId(List<FileDocIdDTO> fileDocIdDTOS) {
        fileDocIdDTOS.stream().forEach(fileDocIdDTO ->{
            uploadFileMapper.updateFileDocId(fileDocIdDTO);
        });
    }

    @Override
    public List<String> getFilePath(String docId, String docType,String businessType) {
        return uploadFileMapper.getFilePath(docId,docType,businessType);
    }


}
